package com.zjsos.governmentaffairs.sokettestapplication.socketClientNew;

import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;

import com.jaydenxiao.common.actionUtil.DeviceUtils;

import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * Created by 张俨 on 2017/10/9.
 */

public class NettyClientNew {

    private static NettyClientNew nettyClient;

    private EventLoopGroup group;
    private NettyListener listener;
    private int requestId = 0;
    private Channel channel;
    private String uuid = DeviceUtils.getMyUUID();
    private boolean isConnect = false;
    private int reconnectNum = Integer.MAX_VALUE;

    private long reconnectIntervalTime = 3000;
    public final static String TAG = NettyClientNew.class.getName();
    private Bootstrap bootstrap;
    private HandlerThread workThread;
    private Handler workHandler;
    public static final int CONNECT = 0;
    public static final int RE_CONNECT = 1;
    public static final int SEND_MESSAGE = 2;
    public static final int DIS_CONNECT = 3;
    public static final int SWITCH_IP_ADDRESS = 4;


    public static NettyClientNew getInstance() {
        if (nettyClient == null) {
            synchronized (NettyClientNew.class) {
                if (nettyClient == null) {
                    nettyClient = new NettyClientNew();
                }
            }
        }
        return nettyClient;
    }

    private NettyClientNew() {
        initNettyClientNew();
    }

    private void initNettyClientNew() {
        workThread = new HandlerThread(NettyClientNew.class.getSimpleName());
        workThread.start();
        workHandler = new Handler(workThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case CONNECT:
                        connect();
                        break;
                    case RE_CONNECT:
                        reconnect();
                        break;
                    case SEND_MESSAGE:
                        Bundle bundle = msg.getData();
                        byte[] requestBytes = bundle.getByteArray("requestBytes");
                        int requestCode = bundle.getInt("requestCode");
                        int responseCode = bundle.getInt("responseCode");
                        NettyClientNew.this.sendMessage(requestBytes, requestCode, responseCode);
                        break;
                    case DIS_CONNECT:
                        disconnect();
                        break;
                    case SWITCH_IP_ADDRESS:
                        switchIpAddress();
                        break;
                }
            }
        };
    }

    //切换ip账号
    private void switchIpAddress() {
        disconnect();
        connect();
    }

    //发送内容
    public void sendContentMessage(byte[] requestBytes, int requestCode, int responseCode) {
        if (!isConnect){
            Log.e("test","重连了。。。。");
            sendReConnectMessage();
            sendEmitterMessage(requestBytes,requestCode,responseCode);
        }else {
            sendEmitterMessage(requestBytes,requestCode,responseCode);
        }
    }


    private void sendEmitterMessage(byte[] requestBytes, int requestCode, int responseCode){
        Message message = new Message();
        message.what = SEND_MESSAGE;
        Bundle bundle = new Bundle();
        bundle.putByteArray("requestBytes", requestBytes);
        bundle.putInt("requestCode", requestCode);
        bundle.putInt("responseCode", responseCode);
        message.setData(bundle);
        workHandler.sendMessage(message);
    }


    public void sendConnectMessage() {
        Message message = workHandler.obtainMessage();
        message.what = CONNECT;
        workHandler.sendMessage(message);
    }


    public void sendSwitchIpAddressMessage() {
        Message message = workHandler.obtainMessage();
        message.what = SWITCH_IP_ADDRESS;
        workHandler.sendMessage(message);
    }

    public void sendReConnectMessage() {
        Message message = workHandler.obtainMessage();
        message.what = RE_CONNECT;
        workHandler.sendMessage(message);
    }


    public void sendDisConnectMessage() {
        Message message = workHandler.obtainMessage();
        message.what = DIS_CONNECT;
        workHandler.sendMessage(message);
    }


    private void connect() {
        String host = "hq.panbao.top";
        int port = 5564;
        Log.e("test","host="+host);
        Log.e("test","port="+port);
        if (!isConnect) {
            group = new NioEventLoopGroup();
            bootstrap = new Bootstrap().group(group)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("ping", new IdleStateHandler(40, 15, 600, TimeUnit.SECONDS));
                            pipeline.addLast(new NettyClientHandlerNew(listener));
                        }
                    });
            try {
                ChannelFuture future = bootstrap.connect(host, port).sync();
                if (future != null && future.isSuccess()) {
                    channel = future.channel();
                    isConnect = true;
                } else {
                    isConnect = false;
                }
                future.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture channelFuture) throws Exception {
                        if (!channelFuture.isSuccess()){
                            final EventLoop loops = channelFuture.channel().eventLoop();
                            loops.schedule(new Runnable() {
                                @Override
                                public void run() {
                                    isConnect=false;
                                    sendReConnectMessage();
                                }
                            }, 1L, TimeUnit.SECONDS);
                        }else {
                            isConnect=true;
                        }
                    }
                });

            } catch (Exception e) {
                e.printStackTrace();
                isConnect=false;
                listener.onServiceStatusConnectChanged(NettyListener.STATUS_CONNECT_ERROR);
                sendReConnectMessage();
            }
        }
    }


    private void disconnect() {
        if (group != null) {
            group.shutdownGracefully();
        }
    }


    private void reconnect() {
        if (reconnectNum > 0 && !isConnect) {
            reconnectNum--;
            try {
                Thread.sleep(reconnectIntervalTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            disconnect();
            connect();
        } else {
            disconnect();
        }
    }



    public Channel getChannel() {
        return channel;
    }


    private void sendMessage(byte[] requestBytes, int requestCode, int responseCode) {
        if (channel==null){
            Log.e("test","channel is null");
            isConnect=false;
            return;
        }
        if (!channel.isOpen()){
            Log.e("test","channel is not open");
            isConnect=false;
            return;
        }
        if (!channel.isWritable()){
            Log.e("test","channel is not writable");
            isConnect=false;
            return;
        }
        if (!channel.isActive()){
            Log.e("test","channel is not active");
            isConnect=false;
            return;
        }
        if (channel != null) {
            channel.writeAndFlush(requestBytes).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    if (channelFuture.isSuccess()) {
                        Log.e(TAG, "发送成功--->");
                    } else {
                        Log.e(TAG, "发送失败--->");
                        isConnect=false;
                    }
                }
            });
        }
    }



    /**
     * 设置重连次数
     *
     * @param reconnectNum 重连次数
     */
    public void setReconnectNum(int reconnectNum) {
        this.reconnectNum = reconnectNum;
    }

    /**
     * 设置重连时间间隔
     *
     * @param reconnectIntervalTime 时间间隔
     */
    public void setReconnectIntervalTime(long reconnectIntervalTime) {
        this.reconnectIntervalTime = reconnectIntervalTime;
    }

    public boolean getConnectStatus() {
        return isConnect;
    }

    /**
     * 设置连接状态
     *
     * @param status
     */
    public void setConnectStatus(boolean status) {
        this.isConnect = status;
    }

    public void setListener(NettyListener listener) {
        if (listener == null) {
            throw new IllegalArgumentException("listener == null ");
        }
        this.listener = listener;
    }


}
